package com.uxsino.simo.indicator;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.uxsino.commons.utils.config.ConfigProp;

public abstract class IndicatorWithRefer extends Indicator {
    /**
     * this indicator depends on these indicator
     */
    @JsonIgnore
    protected List<String> referedIndicatorNames = new ArrayList<>();

    @JsonIgnore
    protected List<Indicator> referedIndicators = new ArrayList<>();

    public IndicatorWithRefer(String indicatorName) {
        super(indicatorName);
    }

    @ConfigProp(name = "refers")
    public void addReferedIndicators(String names) {
        Collections.addAll(referedIndicatorNames, StringUtils.split(names, ","));
    }

    @JsonIgnore
    public List<String> getReferedIndicatorNames() {
        return referedIndicatorNames;
    }

    @JsonIgnore
    public List<Indicator> getReferedIndicators() {
        return referedIndicators;
    }

    /**
     * get referred indicators recursively 
     */
    public void getAllReferedIndicators(Set<Indicator> refered) {
        referedIndicators.stream().filter(ind -> ind instanceof IndicatorWithRefer)
            .forEach(ind -> ((IndicatorWithRefer) ind).getAllReferedIndicators(refered));
        refered.addAll(referedIndicators);

    }

    @JsonIgnore
    public Indicator[] getAllReferedIndicators() {
        Set<Indicator> referred = new HashSet<>();
        getAllReferedIndicators(referred);
        return referred.toArray(new Indicator[referred.size()]);
    }

    public boolean directRefers(Indicator ind) {
        return referedIndicators.contains(ind);
    }

    public boolean refers(Indicator ind) {
        if (directRefers(ind))
            return true;

        for (Indicator ref : referedIndicators) {
            if (ref instanceof IndicatorWithRefer && ((IndicatorWithRefer) ref).refers(ind)) {
                return true;
            }
        }
        return false;
    }

}
